package com.yeyks.commonReference.service.hotel.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sun.media.jfxmedia.logging.Logger;
import com.yeyks.common.constants.ConfigKey;
import com.yeyks.common.dto.mq.GrabTheOrderBToCMessage;
import com.yeyks.common.dto.mq.GrabTheOrderCToBMessage;
import com.yeyks.common.dto.mq.GrabTheOrderCheckMessage;
import com.yeyks.common.pojo.WebSocketBaseSendPojo;
import com.yeyks.common.utils.LocationUtils;
import com.yeyks.common.utils.ValidatorUtil;
import com.yeyks.commonReference.append.getui.service.AppServerGeTuiService;
import com.yeyks.commonReference.append.rocketmq.pojo.RocketMQWebsocketBasePojo;
import com.yeyks.commonReference.append.rocketmq.service.producer.MQProducerService;
import com.yeyks.commonReference.service.config.ConfigService;
import com.yeyks.commonReference.service.hotel.HotelInfoService;
import com.yeyks.commonReference.service.hotel.HotelSearchC2bService;
import com.yeyks.commonReference.service.hotel.HotelSearchUtilService;
import com.yeyks.commonReference.service.hotel.RoomInfoService;
import com.yeyks.commonReference.service.order.OrderPickRecordService;
import com.yeyks.commonReference.service.order.OrderPubRecordService;
import com.yeyks.consumer.dal.domain.UserInfo;
import com.yeyks.consumer.service.UserInfoService;
import com.yeyks.hotel.dal.domain.HotelInfo;
import com.yeyks.hotel.dal.domain.RoomInfo;
import com.yeyks.hotel.param.GrabTheOrderServiceGetNowGrabTheOrderedHotelListParam;
import com.yeyks.hotel.param.GrabTheOrderServiceGrabTheOrderParam;
import com.yeyks.hotel.utils.HotelSearchUtil;
import com.yeyks.hotel.vo.*;
import com.yeyks.order.dal.domain.OrderPickRecord;
import com.yeyks.order.dal.domain.OrderPubRecord;
import com.yeyks.search.pojo.param.esSearch.EsHotelSearchBaseServiceSearchC2bHotelListParam;
import com.yeyks.search.pojo.param.esSearch.EsHotelSearchBaseServiceSearchC2bHotelListParamRoomParam;
import com.yeyks.search.pojo.param.search.HotelSearchC2bListParam;
import com.yeyks.search.pojo.vo.search.HotelInfoHotelSearchVoForApp;
import com.yeyks.search.pojo.vo.search.HotelInfoHotelUnionSearchVo;
import com.yeyks.search.service.hotel.EsHotelSearchC2bService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * v3.4
 */
@Service
@Slf4j
public class HotelSearchC2bServiceImpl implements HotelSearchC2bService {

    @Autowired
    private MQProducerService mqProducerService;
    @Autowired(required = false)
    private AppServerGeTuiService appServerGeTuiService;
    @Autowired
    private OrderPubRecordService orderPubRecordService;
    @Autowired
    private OrderPickRecordService orderPickRecordService;
    @Autowired
    private HotelInfoService hotelInfoService;
    @Autowired
    private HotelSearchUtilService hotelSearchUtilService;
    @Autowired
    private RoomInfoService roomInfoService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private EsHotelSearchC2bService esHotelSearchC2bService;

    //保存抢单记录并向服务器发送记录  v3.4
    @Override
    public GrabTheOrderServiceGrabTheOrderVo grabTheOrder(GrabTheOrderServiceGrabTheOrderParam param) {
        GrabTheOrderServiceGrabTheOrderVo grabTheOrderServiceGrabTheOrderVo = new GrabTheOrderServiceGrabTheOrderVo();
        grabTheOrderServiceGrabTheOrderVo.setTimingTime((Convert.toInt(configService.getValue(ConfigKey.C2B_ROB_OVERTIME), 15) + 3));
        //校验参数
        ValidatorUtil.validateEntity(param);
//        //时间修正
//        param.setStartDate(HotelSearchUtil.fixDate(param.getStartDate()));
//        param.setEndDate(HotelSearchUtil.fixDate(param.getEndDate()));
        //时间校验
        HotelSearchUtil.checkSearchDate(param.getStartDate(), param.getEndDate());
        //检查是否是已发送的抢单
        OrderPubRecord orderPubRecordOld = orderPubRecordService.getOne(
                new QueryWrapper<OrderPubRecord>()
                        .eq(OrderPubRecord.USER_ID, param.getUserId())
                        .eq(OrderPubRecord.TIMESTAMP, param.getTimestamp())
        );
        if (Objects.nonNull(orderPubRecordOld)) {
            return grabTheOrderServiceGrabTheOrderVo.setSuccess(false);
        }
        //查询用户
        UserInfo userInfo = userInfoService.getById(param.getUserId());
        //保存记录
        Date date = new Date();
        OrderPubRecord orderPubRecord = new OrderPubRecord();
        orderPubRecord.setGmtCreate(date);
        orderPubRecord.setGmtModified(date);
        orderPubRecord.setTimestamp(param.getTimestamp());
        orderPubRecord.setUserId(param.getUserId());
        orderPubRecord.setPrice(param.getPrice());
        orderPubRecord.setStartDate(param.getStartDate());
        orderPubRecord.setEndDate(param.getEndDate());
        orderPubRecord.setStatus(0);
        orderPubRecord.setPositionX(param.getPositionX());
        orderPubRecord.setPositionY(param.getPositionY());
        orderPubRecord.setCity(param.getCity());
        orderPubRecord.setComfortLevel(param.getComfortLevel());
        orderPubRecord.setSource(param.getSource());
        orderPubRecord.setPhone(userInfo.getPhone());
        orderPubRecordService.save(orderPubRecord);
        //向服务器发送抢单消息
        mqProducerService.sendGrabTheOrderCToBMsg(new GrabTheOrderCToBMessage().setOrderPubRecordId(orderPubRecord.getId()));
        //10分钟后进行订单超时记录的处理
        mqProducerService.sendGrabTheOrderCheckMsg(new GrabTheOrderCheckMessage().setOrderPubRecordId(orderPubRecord.getId()));
        return grabTheOrderServiceGrabTheOrderVo.setSuccess(true);
    }

    //----------------------------------------------------------------------------------------------------

    //获取目前已抢单的酒店记录  v3.4
    @Override
    @Deprecated
    public HotelInfoHotelSearchVo getNowAllGrabTheOrderedHotelListVo(GrabTheOrderServiceGetNowGrabTheOrderedHotelListParam param) {
        return covertToHotelInfoHotelSearchVo(getNowAllGrabTheOrderedHotelList(param));
    }

    //包装返回对象
    @Deprecated
    public HotelInfoHotelSearchVo covertToHotelInfoHotelSearchVo(List<HotelInfoHotelSearchVoHotle> hotelInfoHotelSearchVoHotles) {
        HotelInfoHotelSearchVo hotelInfoHotelSearchVo = new HotelInfoHotelSearchVo();
        hotelInfoHotelSearchVo.setList(hotelInfoHotelSearchVoHotles);
        return hotelInfoHotelSearchVo;
    }

    //当前酒店记录
    @Deprecated
    public List<HotelInfoHotelSearchVoHotle> getNowAllGrabTheOrderedHotelList(GrabTheOrderServiceGetNowGrabTheOrderedHotelListParam param) {
        List<HotelInfoHotelSearchVoHotle> hotelInfoHotelSearchVoHotles = getNowGrabTheOrderedHotelList(param);
        sortHotelInfoHotelSearchVoHotles(hotelInfoHotelSearchVoHotles, param.getSort());
        return hotelInfoHotelSearchVoHotles;
    }

    //所有抢单的酒店
    @Deprecated
    public List<HotelInfoHotelSearchVoHotle> getNowGrabTheOrderedHotelList(GrabTheOrderServiceGetNowGrabTheOrderedHotelListParam param) {
        List<OrderPickRecord> orderPickRecords = orderPickRecordService.list(
                new QueryWrapper<OrderPickRecord>()
                        .eq(OrderPickRecord.USER_ID, param.getUserId())
                        .eq(OrderPickRecord.TIMESTAMP, param.getTimestamp())
        );
        return convertOrderPickRecordsToGrabTheOrderServiceHotelAndRoomVos(orderPickRecords);
    }

    //酒店排序
    @Deprecated
    private void sortHotelInfoHotelSearchVoHotles(List<HotelInfoHotelSearchVoHotle> hotelInfoHotelSearchVoHotles, Integer sort) {
        hotelInfoHotelSearchVoHotles.sort((o1, o2) -> {
            //1智能，2距离，3价格
            switch (sort) {
                case 2:
                    //距离由进到远
                    return CompareUtil.compare(o1.getDistance(), o2.getDistance());
                case 3:
                    //价格由高到低
                    Integer o1Price = o1.getRooms().get(0).getCurPrice();
                    for (RoomInfo roomInfo : o1.getRooms()) {
                        if (o1Price > roomInfo.getCurPrice()) {
                            o1Price = roomInfo.getCurPrice();
                        }
                    }
                    Integer o2Price = o2.getRooms().get(0).getCurPrice();
                    for (RoomInfo roomInfo : o2.getRooms()) {
                        if (o2Price > roomInfo.getCurPrice()) {
                            o2Price = roomInfo.getCurPrice();
                        }
                    }
                    return CompareUtil.compare(o2Price, o1Price);
                case 1:
                default:
                    //默认智能排序,评分由高到低
                    return CompareUtil.compare(o2.getScore(), o1.getScore());
            }
        });
    }

    //将抢单记录转成酒店列表信息 v3.4
    @Override
    @Deprecated
    public List<HotelInfoHotelSearchVoHotle> convertOrderPickRecordsToGrabTheOrderServiceHotelAndRoomVos(List<OrderPickRecord> orderPickRecords) {
        if (null == orderPickRecords || orderPickRecords.size() < 1) {
            return new ArrayList<>();
        }
        //查询发布信息
        OrderPubRecord orderPubRecord = orderPubRecordService.getOne(
                new QueryWrapper<OrderPubRecord>()
                        .eq(OrderPubRecord.USER_ID, orderPickRecords.get(0).getUserId())
                        .eq(OrderPubRecord.TIMESTAMP, orderPickRecords.get(0).getTimestamp())
                        .last("limit 1")
        );
        if (Objects.isNull(orderPubRecord)) {
            return new ArrayList<>();
        }
        //整理查询条件
        HashSet<Integer> hotelIds = new HashSet<>();
        HashSet<Integer> roomIds = new HashSet<>();
        for (OrderPickRecord orderPickRecord : orderPickRecords) {
            hotelIds.add(orderPickRecord.getHotelId());
            roomIds.add(orderPickRecord.getRoomId());
        }
        //查酒店
        List<HotelInfo> hotelInfos = hotelInfoService.list(new QueryWrapper<HotelInfo>().in(HotelInfo.ID, hotelIds));
        //查房间
        List<RoomInfo> roomInfos = roomInfoService.list(new QueryWrapper<RoomInfo>().in(RoomInfo.ID, roomIds));
        //拼接数据
        ArrayList<HotelInfoHotelSearchVoHotle> hotelInfoHotelSearchVoHotles = new ArrayList<>();
        for (HotelInfo hotelInfo : hotelInfos) {
            //添加酒店信息
            HotelInfoHotelSearchVoHotle hotelInfoHotelSearchVoHotle = new HotelInfoHotelSearchVoHotle();
            BeanUtil.copyProperties(hotelInfo, hotelInfoHotelSearchVoHotle);
            //填充距离
            try {
                hotelInfoHotelSearchVoHotle.setDistance(LocationUtils.getDistance(
                        hotelInfoHotelSearchVoHotle.getPositionY()
                        , hotelInfoHotelSearchVoHotle.getPositionX()
                        , orderPubRecord.getPositionY()
                        , orderPubRecord.getPositionX()
                ).intValue());
            } catch (Exception e) {
                e.printStackTrace();
            }
            hotelInfoHotelSearchVoHotles.add(hotelInfoHotelSearchVoHotle);
            //添加房间信息
            ArrayList<HotelInfoHotelSearchVoRoom> hotelInfoHotelSearchVoRooms = new ArrayList<>();
            Iterator<RoomInfo> iterator = roomInfos.iterator();
            while (iterator.hasNext()) {
                RoomInfo roomInfo = iterator.next();
                if (hotelInfo.getId().equals(roomInfo.getHotelId())) {
                    HotelInfoHotelSearchVoRoom hotelInfoHotelSearchVoRoom = new HotelInfoHotelSearchVoRoom();
                    BeanUtil.copyProperties(roomInfo, hotelInfoHotelSearchVoRoom);
                    hotelInfoHotelSearchVoRooms.add(hotelInfoHotelSearchVoRoom);
                    iterator.remove();
                }
            }
            hotelInfoHotelSearchVoHotle.setRooms(hotelInfoHotelSearchVoRooms);
            //完善roomIds
            StringJoiner sj = new StringJoiner(",");
            for (HotelInfoHotelSearchVoRoom hotelInfoHotelSearchVoRoom : hotelInfoHotelSearchVoRooms) {
                sj.add(hotelInfoHotelSearchVoRoom.getId().toString());
            }
            hotelInfoHotelSearchVoHotle.setRoomIds(sj.toString());
            //房态
            hotelSearchUtilService.perfectHotelInfoB2cHotelSearchVoRoomsAttribute(hotelInfoHotelSearchVoHotle, orderPubRecord.getStartDate(), orderPubRecord.getEndDate());
        }
        return hotelInfoHotelSearchVoHotles;
    }

    //----------------------------------------------------------------------------------------------------

    //推送抢单消息 v3.4
    @Override
    public void sendGrabTheOrderResult(GrabTheOrderBToCMessage message) {
        //个推的长消息分割载体
        List<WebSocketBaseSendPojo> webSocketBaseSendPojoList = new ArrayList<>();
        //普通消息发送的消息体
        WebSocketBaseSendPojo webSocketBaseSendPojo = new WebSocketBaseSendPojo();
        webSocketBaseSendPojo.setType(message.getCode());
        webSocketBaseSendPojo.setTimestamp(message.getTimestamp());
        //获取来源
        OrderPubRecord orderPubRecord = orderPubRecordService.getOne(
                new QueryWrapper<OrderPubRecord>()
                        .eq(OrderPubRecord.USER_ID, message.getUserId())
                        .eq(OrderPubRecord.TIMESTAMP, message.getTimestamp())
                        .last("limit 1")
        );
        switch (message.getCode()) {
            //不存在酒店
            case 1:
                webSocketBaseSendPojo.setDataStr("该地区暂无符合条件的酒店");
                break;
            //不存在手动抢单酒店
            case 2:
                webSocketBaseSendPojo.setDataStr("");
                break;
            case 4:
                webSocketBaseSendPojo.setDataStr("无抢单请求");
                break;
            case 5:
                webSocketBaseSendPojo.setDataStr("参数错误");
                break;
            //手动抢单列表
            case 3:
                //自动抢单列表
            case 11:
                //v3.6
                HotelSearchC2bListParam hotelSearchC2bListParam = new HotelSearchC2bListParam();
                hotelSearchC2bListParam.setUserId(message.getUserId());
                hotelSearchC2bListParam.setPickIds(message.getOrderPickRecordIds());
                hotelSearchC2bListParam.setManualPickOrder((message.getCode() == 11) ? 0 : null);
                hotelSearchC2bListParam.setTimestamp(message.getTimestamp());
                HotelInfoHotelUnionSearchVo grabTheOrderedHotelList = getGrabTheOrderedHotelList(hotelSearchC2bListParam);
                switch (orderPubRecord.getSource()) {
                    case "JS":
                    case "iOS":
                    case "Android":
                        //简化数据长度
                        HotelInfoHotelSearchVoForApp hotelInfoHotelSearchVoForApp = HotelInfoHotelSearchVoForApp.covertHotelInfoHotelSearchVo(grabTheOrderedHotelList);
                        webSocketBaseSendPojo.setDataStr(JSONUtil.toJsonStr(hotelInfoHotelSearchVoForApp));
                        //切割数据
                        List<HotelInfoHotelSearchVoHotleForApp> hotelInfoHotelSearchVoForAppList = hotelInfoHotelSearchVoForApp.getList();
                        while (CollectionUtil.isNotEmpty(hotelInfoHotelSearchVoForAppList)) {
                            int count = 10;
                            ArrayList<HotelInfoHotelSearchVoHotleForApp> sendList = new ArrayList<>();
                            while (count-- > 0 && CollectionUtil.isNotEmpty(hotelInfoHotelSearchVoForAppList)) {
                                sendList.add(hotelInfoHotelSearchVoForAppList.remove(0));
                            }
                            if (CollectionUtil.isNotEmpty(sendList)) {
                                WebSocketBaseSendPojo socketBaseSendPojo = BeanUtil.toBean(webSocketBaseSendPojo, WebSocketBaseSendPojo.class);
                                socketBaseSendPojo.setDataStr(JSONUtil.toJsonStr(new HotelInfoHotelSearchVoForApp().setList(sendList)));
                                webSocketBaseSendPojoList.add(socketBaseSendPojo);
                            }
                        }
                        break;
                }
                break;
            default:
                break;
        }
        if (Objects.nonNull(orderPubRecord)) {
            //根据来源发送消息
            switch (orderPubRecord.getSource()) {
                case "JS":
                    if (CollectionUtil.isNotEmpty(webSocketBaseSendPojoList)) {
                        for (WebSocketBaseSendPojo socketBaseSendPojo : webSocketBaseSendPojoList) {
                            RocketMQWebsocketBasePojo rocketMQWebsocketBasePojo = new RocketMQWebsocketBasePojo();
                            rocketMQWebsocketBasePojo.setUserId(message.getUserId());
                            rocketMQWebsocketBasePojo.setBody(JSONUtil.toJsonStr(socketBaseSendPojo));
                            mqProducerService.sendGrabTheOrderWebsocketMsg(rocketMQWebsocketBasePojo);
                        }
                    } else {
                        RocketMQWebsocketBasePojo rocketMQWebsocketBasePojo = new RocketMQWebsocketBasePojo();
                        rocketMQWebsocketBasePojo.setUserId(message.getUserId());
                        rocketMQWebsocketBasePojo.setBody(JSONUtil.toJsonStr(webSocketBaseSendPojo));
                        mqProducerService.sendGrabTheOrderWebsocketMsg(rocketMQWebsocketBasePojo);
                    }
                    break;
                case "iOS":
                case "Android":
                    if (CollectionUtil.isNotEmpty(webSocketBaseSendPojoList)) {
                        String res =  "";
                        for (WebSocketBaseSendPojo socketBaseSendPojo : webSocketBaseSendPojoList) {
                             res = JSONUtil.toJsonStr(socketBaseSendPojo);
                            log.info("开始把抢单结果分每10条推送给用户指定用户{}推送结果数量:{}", message.getUserId(),socketBaseSendPojo.getDataStr().split("name").length);
                            //临时解决推送debug或延时才能收到的问题
                            Long sleepTime = Long.valueOf(String.valueOf(configService.getValueWithDefault("orderPick.push.sleep.time",1500)));
                            if(sleepTime!=0){
                                try {
                                    Thread.sleep(sleepTime);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                            appServerGeTuiService.singlePushOffline(String.valueOf(message.getUserId()), "GrabTheOrderResult", res);
                            log.info("推送用户{}结束",message.getUserId());
                        }
                    } else {
                        appServerGeTuiService.singlePushOffline(String.valueOf(message.getUserId()), "GrabTheOrderResult", JSONUtil.toJsonStr(webSocketBaseSendPojo));
                    }
                    break;
            }
        }
    }

    //----------------------------------------------------------------------------------------------------


    //获取目前已抢单的酒店记录,可以是全部,可以按类型,可以按记录id  v3.6
    @Override
    public HotelInfoHotelUnionSearchVo getGrabTheOrderedHotelList(HotelSearchC2bListParam param) {
        //查询抢单信息
        QueryWrapper<OrderPickRecord> orderPickRecordQueryWrapper = new QueryWrapper<OrderPickRecord>()
                .eq(OrderPickRecord.USER_ID, param.getUserId())
                .eq(OrderPickRecord.TIMESTAMP, param.getTimestamp());
        if (CollectionUtil.isNotEmpty(param.getPickIds())) {
            orderPickRecordQueryWrapper.in(OrderPickRecord.ID, param.getPickIds().toArray());
        }
        if (Objects.nonNull(param.getManualPickOrder())) {
            orderPickRecordQueryWrapper.eq(OrderPickRecord.MANUAL_PICK_ORDER, param.getManualPickOrder());
        }
        if (StrUtil.isNotBlank(param.getSourceType())) {
            orderPickRecordQueryWrapper.eq(OrderPickRecord.SOURCE_TYPE, param.getSourceType());
        }
        if (StrUtil.isNotBlank(param.getHotelId())) {
            orderPickRecordQueryWrapper.eq(OrderPickRecord.SOURE_HOTEL_ID, param.getHotelId());
        }
        if (StrUtil.isNotBlank(param.getRoomId())) {
            orderPickRecordQueryWrapper.eq(OrderPickRecord.SOURCE_ROOM_ID, param.getRoomId());
        }
        List<OrderPickRecord> orderPickRecords = orderPickRecordService.list(orderPickRecordQueryWrapper);
        if (null == orderPickRecords || orderPickRecords.size() < 1) {
            return new HotelInfoHotelUnionSearchVo();
        }
        //查询发布信息
        OrderPubRecord orderPubRecord = orderPubRecordService.getOne(
                new QueryWrapper<OrderPubRecord>()
                        .eq(OrderPubRecord.USER_ID, orderPickRecords.get(0).getUserId())
                        .eq(OrderPubRecord.TIMESTAMP, orderPickRecords.get(0).getTimestamp())
                        .last("limit 1")
        );
        if (Objects.isNull(orderPubRecord)) {
            return new HotelInfoHotelUnionSearchVo();
        }
        //整理查询条件
        ArrayList<EsHotelSearchBaseServiceSearchC2bHotelListParamRoomParam> roomParamArrayList = new ArrayList<>();
        for (OrderPickRecord orderPickRecord : orderPickRecords) {
            EsHotelSearchBaseServiceSearchC2bHotelListParamRoomParam paramRoomParam = new EsHotelSearchBaseServiceSearchC2bHotelListParamRoomParam();
            paramRoomParam.setSourceType(orderPickRecord.getSourceType());
            paramRoomParam.setSourceHotelId(orderPickRecord.getSoureHotelId());
            paramRoomParam.setSourceRoomId(orderPickRecord.getSourceRoomId());
            roomParamArrayList.add(paramRoomParam);
        }

        EsHotelSearchBaseServiceSearchC2bHotelListParam esHotelSearchBaseServiceSearchC2bHotelListParam = new EsHotelSearchBaseServiceSearchC2bHotelListParam();
        esHotelSearchBaseServiceSearchC2bHotelListParam.setRoomParams(roomParamArrayList);
        esHotelSearchBaseServiceSearchC2bHotelListParam.setPositionX(orderPubRecord.getPositionX());
        esHotelSearchBaseServiceSearchC2bHotelListParam.setPositionY(orderPubRecord.getPositionY());
        esHotelSearchBaseServiceSearchC2bHotelListParam.setStartTime(orderPubRecord.getStartDate());
        esHotelSearchBaseServiceSearchC2bHotelListParam.setEndTime(orderPubRecord.getEndDate());
        esHotelSearchBaseServiceSearchC2bHotelListParam.setSort(param.getSort());
        esHotelSearchBaseServiceSearchC2bHotelListParam.setPrice(orderPubRecord.getPrice());

        return esHotelSearchC2bService.getList(esHotelSearchBaseServiceSearchC2bHotelListParam);
    }

    //----------------------------------------------------------------------------------------------------

}
